home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / softwareproperties / SoftwareProperties.pyc (.txt) < prev   
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  22.7 KB  |  614 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. import apt_pkg
  5. from hashlib import md5
  6. import re
  7. import os
  8. import glob
  9. import sys
  10. import shutil
  11. import subprocess
  12. from tempfile import NamedTemporaryFile
  13. import string
  14. from xml.sax.saxutils import escape
  15. from ConfigParser import ConfigParser
  16. from gettext import gettext as _
  17. from AptAuth import AptAuth
  18. import softwareproperties
  19. import aptsources
  20. import aptsources.distro as aptsources
  21. from aptsources.sourceslist import SourcesList, SourceEntry
  22.  
  23. class SoftwareProperties(object):
  24.     CHANNEL_PATH = '/usr/share/app-install/channels/'
  25.     RELEASE_UPGRADES_CONF = '/etc/update-manager/release-upgrades'
  26.     (RELEASE_UPGRADES_NEVER, RELEASE_UPGRADES_NORMAL, RELEASE_UPGRADES_LTS) = range(3)
  27.     release_upgrades_policy_map = {
  28.         RELEASE_UPGRADES_NEVER: 'never',
  29.         RELEASE_UPGRADES_NORMAL: 'normal',
  30.         RELEASE_UPGRADES_LTS: 'lts' }
  31.     
  32.     def __init__(self, datadir = None, options = None):
  33.         ''' Provides the core functionality to configure the used software 
  34.         repositories, the corresponding authentication keys and 
  35.         update automation '''
  36.         self.popconfile = '/etc/popularity-contest.conf'
  37.         if datadir == None:
  38.             datadir = '/usr/share/software-properties/'
  39.         
  40.         self.datadir = datadir
  41.         self.sourceslist = SourcesList()
  42.         self.distro = aptsources.distro.get_distro()
  43.         self.seen_server = []
  44.         self.modified_sourceslist = False
  45.         self.reload_sourceslist()
  46.         self.backup_sourceslist()
  47.         self.backup_apt_conf()
  48.         self.custom_mirrors = []
  49.         self.apt_key = AptAuth()
  50.  
  51.     
  52.     def backup_apt_conf(self):
  53.         '''Backup all apt configuration options'''
  54.         self.apt_conf_backup = { }
  55.         for option in softwareproperties.CONF_MAP.keys():
  56.             value = apt_pkg.Config.FindI(softwareproperties.CONF_MAP[option])
  57.             self.apt_conf_backup[option] = value
  58.         
  59.  
  60.     
  61.     def restore_apt_conf(self):
  62.         '''Restore the stored apt configuration'''
  63.         for option in self.apt_conf_backup.keys():
  64.             apt_pkg.Config.Set(softwareproperties.CONF_MAP[option], str(self.apt_conf_backup[option]))
  65.         
  66.         self.write_config()
  67.  
  68.     
  69.     def get_update_automation_level(self):
  70.         ''' Parse the apt cron configuration. Try to fit a predefined use case 
  71.         and return it. Special case: if the user made a custom 
  72.         configurtation, that we cannot represent it will return None '''
  73.         if apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autoupdate']) > 0:
  74.             if apt_pkg.Config.FindI(softwareproperties.CONF_MAP['unattended']) == 1 and apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autodownload']) == 1:
  75.                 return softwareproperties.UPDATE_INST_SEC
  76.             if apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autodownload']) == 1 and apt_pkg.Config.FindI(softwareproperties.CONF_MAP['unattended']) == 0:
  77.                 return softwareproperties.UPDATE_DOWNLOAD
  78.             if apt_pkg.Config.FindI(softwareproperties.CONF_MAP['unattended']) == 0 and apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autodownload']) == 0:
  79.                 return softwareproperties.UPDATE_NOTIFY
  80.             return None
  81.         apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autoupdate']) > 0
  82.         if apt_pkg.Config.FindI(softwareproperties.CONF_MAP['unattended']) == 0 and apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autodownload']) == 0:
  83.             return softwareproperties.UPDATE_MANUAL
  84.         return None
  85.  
  86.     
  87.     def set_update_automation_level(self, state):
  88.         ''' Set the apt periodic configurtation to the selected 
  89.         update automation level. To synchronize the cache update and the 
  90.         actual upgrading function, the upgrade function, e.g. unattended, 
  91.         will run every day, if enabled. '''
  92.         if state == softwareproperties.UPDATE_INST_SEC:
  93.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['unattended'], str(1))
  94.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autodownload'], str(1))
  95.         elif state == softwareproperties.UPDATE_DOWNLOAD:
  96.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autodownload'], str(1))
  97.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['unattended'], str(0))
  98.         elif state == softwareproperties.UPDATE_NOTIFY:
  99.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autodownload'], str(0))
  100.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['unattended'], str(0))
  101.         else:
  102.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autoupdate'], str(0))
  103.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['unattended'], str(0))
  104.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autodownload'], str(0))
  105.         self.set_modified_config()
  106.  
  107.     
  108.     def set_update_interval(self, days):
  109.         '''Set the interval in which we check for available updates'''
  110.         if not days == apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autoupdate']):
  111.             apt_pkg.Config.Set(softwareproperties.CONF_MAP['autoupdate'], str(days))
  112.             self.set_modified_config()
  113.         
  114.  
  115.     
  116.     def get_update_interval(self):
  117.         ''' Returns the interval of the apt periodic cron job '''
  118.         return apt_pkg.Config.FindI(softwareproperties.CONF_MAP['autoupdate'])
  119.  
  120.     
  121.     def get_release_upgrades_policy(self):
  122.         '''
  123.     return the release upgrade policy:
  124.      RELASE_UPGRADE_NEVER
  125.      RELASE_UPGRADE_NORMAL
  126.      RELASE_UPGRADE_LTS
  127.     '''
  128.         if not os.path.exists(self.RELEASE_UPGRADES_CONF):
  129.             return self.RELEASE_UPGRADES_NORMAL
  130.         parser = ConfigParser()
  131.         parser.read(self.RELEASE_UPGRADES_CONF)
  132.         return self.RELEASE_UPGRADES_NORMAL
  133.  
  134.     
  135.     def set_release_upgrades_policy(self, i):
  136.         '''
  137.     set the release upgrade policy:
  138.      RELASE_UPGRADE_NEVER
  139.      RELASE_UPGRADE_NORMAL
  140.      RELASE_UPGRADE_LTS
  141.      '''
  142.         if not os.path.exists(self.RELEASE_UPGRADES_CONF):
  143.             f = open(self.RELEASE_UPGRADES_CONF, 'w')
  144.             f.write('[DEFAULT]\nprompt=%s\n' % self.release_upgrades_policy_map[i])
  145.             return True
  146.         f = open(self.RELEASE_UPGRADES_CONF, 'r')
  147.         out = NamedTemporaryFile()
  148.         for line in map(string.strip, f.readlines()):
  149.             if line.lower().startswith('prompt'):
  150.                 out.write('prompt=%s\n' % self.release_upgrades_policy_map[i])
  151.                 continue
  152.             os.path.exists(self.RELEASE_UPGRADES_CONF)
  153.             out.write(line + '\n')
  154.         
  155.         out.flush()
  156.         shutil.copymode(self.RELEASE_UPGRADES_CONF, out.name)
  157.         shutil.copy(out.name, self.RELEASE_UPGRADES_CONF)
  158.         return True
  159.  
  160.     
  161.     def get_popcon_participation(self):
  162.         ''' Will return True if the user wants to participate in the popularity 
  163.         contest. Otherwise it will return False. Special case: if no 
  164.         popcon is installed it will return False '''
  165.         if os.path.exists(self.popconfile):
  166.             lines = open(self.popconfile).read().split('\n')
  167.             active = False
  168.             for line in lines:
  169.                 
  170.                 try:
  171.                     (key, value) = line.split('=')
  172.                     if key == 'PARTICIPATE' and value.strip('"').lower() == 'yes':
  173.                         active = True
  174.                 continue
  175.                 except ValueError:
  176.                     continue
  177.                     continue
  178.                 
  179.  
  180.             
  181.             return active
  182.         return False
  183.  
  184.     
  185.     def set_popcon_pariticipation(self, is_helpful):
  186.         ''' Enable or disable the participation in the popularity contest '''
  187.         if is_helpful == True:
  188.             value = 'yes'
  189.         else:
  190.             value = 'no'
  191.         if os.path.exists(self.popconfile):
  192.             lines = (map,)((lambda line: re.sub('^(PARTICIPATE=)(".+?")', '\\1"%s"' % value, line)), open(self.popconfile, 'r').readlines())
  193.         else:
  194.             m = md5()
  195.             m.update(open('/dev/urandom', 'r').read(1024))
  196.             id = m.hexdigest()
  197.             lines = []
  198.             lines.append('MY_HOSTID="%s"\n' % id)
  199.             lines.append('PARTICIPATE="%s"\n' % str(value))
  200.             lines.append('USE_HTTP="yes"\n')
  201.         open(self.popconfile, 'w').writelines(lines)
  202.  
  203.     
  204.     def get_source_code_state(self):
  205.         '''Return True if all distro componets are also available as 
  206.        source code. Otherwise return Flase. Special case: If the
  207.        configuration cannot be represented return None'''
  208.         if len(self.distro.source_code_sources) < 1:
  209.             self.distro.get_source_code = False
  210.             return False
  211.         self.distro.get_source_code = True
  212.         templates = { }
  213.         sources = []
  214.         sources.extend(self.distro.main_sources)
  215.         sources.extend(self.distro.child_sources)
  216.         for source in sources:
  217.             if templates.has_key(source.template):
  218.                 for comp in source.comps:
  219.                     templates[source.template].add(comp)
  220.                 
  221.             len(self.distro.source_code_sources) < 1
  222.             templates[source.template] = set(source.comps)
  223.         
  224.         if len(self.distro.cdrom_sources) > 0:
  225.             templates[self.distro.source_template] = self.distro.cdrom_comps
  226.         
  227.         for source in self.distro.source_code_sources:
  228.             if not templates.has_key(source.template) or templates.has_key(source.template):
  229.                 if not len(set(templates[source.template]) ^ set(source.comps)) == 0:
  230.                     pass
  231.                 if not (len(set(source.comps) ^ self.distro.enabled_comps) == 0):
  232.                     self.distro.get_source_code = False
  233.                     return None
  234.                 continue
  235.             not (len(set(source.comps) ^ self.distro.enabled_comps) == 0)
  236.         
  237.         return True
  238.  
  239.     
  240.     def print_source_entry(self, source):
  241.         '''Print the data of a source entry to the command line'''
  242.         for label, value in [
  243.             ('URI:', source.uri),
  244.             ('Comps:', source.comps),
  245.             ('Enabled:', not (source.disabled)),
  246.             ('Valid:', not (source.invalid))]:
  247.             print ' %s %s' % (label, value)
  248.         
  249.         if source.template:
  250.             for label, value in [
  251.                 ('MatchURI:', source.template.match_uri),
  252.                 ('BaseURI:', source.template.base_uri)]:
  253.                 print ' %s %s' % (label, value)
  254.             
  255.         
  256.         print '\n'
  257.  
  258.     
  259.     def massive_debug_output(self):
  260.         '''Print the complete sources.list'''
  261.         print 'START SOURCES.LIST:'
  262.         for source in self.sourceslist:
  263.             print source.str()
  264.         
  265.         print 'END SOURCES.LIST\n'
  266.  
  267.     
  268.     def enable_component(self, comp):
  269.         '''Enable a component of the distro'''
  270.         self.distro.enable_component(comp)
  271.         self.set_modified_sourceslist()
  272.  
  273.     
  274.     def disable_component(self, comp):
  275.         '''Disable a component of the distro'''
  276.         self.distro.disable_component(comp)
  277.         self.set_modified_sourceslist()
  278.  
  279.     
  280.     def disable_child_source(self, template):
  281.         '''Enable a child repo of the distribution main repository'''
  282.         for source in self.distro.child_sources:
  283.             if source.template == template:
  284.                 self.sourceslist.remove(source)
  285.                 continue
  286.         
  287.         for source in self.distro.source_code_sources:
  288.             if source.template == template:
  289.                 self.sourceslist.remove(source)
  290.                 continue
  291.         
  292.         self.set_modified_sourceslist()
  293.  
  294.     
  295.     def enable_child_source(self, template):
  296.         '''Enable a child repo of the distribution main repository'''
  297.         if template.base_uri == None:
  298.             child_uri = self.distro.default_server
  299.         else:
  300.             child_uri = template.base_uri
  301.         self.distro.add_source(uri = child_uri, dist = template.name)
  302.         self.set_modified_sourceslist()
  303.  
  304.     
  305.     def disable_source_code_sources(self):
  306.         '''Remove all distro source code sources'''
  307.         sources = []
  308.         sources.extend(self.distro.main_sources)
  309.         sources.extend(self.distro.child_sources)
  310.         for source in self.distro.source_code_sources:
  311.             self.sourceslist.remove(source)
  312.         
  313.         self.set_modified_sourceslist()
  314.  
  315.     
  316.     def enable_source_code_sources(self):
  317.         '''Enable source code source for all distro sources'''
  318.         sources = []
  319.         sources.extend(self.distro.main_sources)
  320.         sources.extend(self.distro.child_sources)
  321.         for source in self.distro.source_code_sources:
  322.             self.sourceslist.remove(source)
  323.         
  324.         for source in sources:
  325.             self.sourceslist.add('deb-src', source.uri, source.dist, source.comps, 'Added by software-properties', self.sourceslist.list.index(source) + 1, source.file)
  326.         
  327.         for source in self.distro.cdrom_sources:
  328.             self.sourceslist.add('deb-src', self.distro.source_template.base_uri, self.distro.source_template.name, source.comps, 'Added by software-properties', self.sourceslist.list.index(source) + 1, source.file)
  329.         
  330.         self.set_modified_sourceslist()
  331.  
  332.     
  333.     def backup_sourceslist(self):
  334.         '''Store a backup of the source.list in memory'''
  335.         self.sourceslist_backup = []
  336.         for source in self.sourceslist.list:
  337.             source_bkp = SourceEntry(line = source.line, file = source.file)
  338.             self.sourceslist_backup.append(source_bkp)
  339.         
  340.  
  341.     
  342.     def toggle_source_use(self, source):
  343.         '''Enable or disable the selected channel'''
  344.         source.disabled = not (source.disabled)
  345.         self.set_modified_sourceslist()
  346.  
  347.     
  348.     def revert(self):
  349.         '''Revert all settings to the state when software-properties 
  350.        was launched'''
  351.         self.restore_apt_conf()
  352.         self.revert_sourceslist()
  353.  
  354.     
  355.     def revert_sourceslist(self):
  356.         '''Restore the source list from the startup of the dialog'''
  357.         self.sourceslist.list = []
  358.         for source in self.sourceslist_backup:
  359.             source_reset = SourceEntry(line = source.line, file = source.file)
  360.             self.sourceslist.list.append(source_reset)
  361.         
  362.         self.save_sourceslist()
  363.         self.reload_sourceslist()
  364.  
  365.     
  366.     def set_modified_sourceslist(self):
  367.         '''The sources list was changed and now needs to be saved and reloaded'''
  368.         self.modified_sourceslist = True
  369.         if self.options.massive_debug == True:
  370.             self.massive_debug_output()
  371.         
  372.         self.save_sourceslist()
  373.         self.reload_sourceslist()
  374.  
  375.     
  376.     def set_modified_config(self):
  377.         '''Write the changed apt configuration to file'''
  378.         self.write_config()
  379.  
  380.     
  381.     def render_source(self, source):
  382.         '''Render a nice output to show the source in a treeview'''
  383.         if source.template == None:
  384.             if source.comment:
  385.                 contents = '<b>%s</b>' % escape(source.comment)
  386.                 if len(source.comps) > 1:
  387.                     for c in source.comps:
  388.                         contents += ' %s' % c
  389.                     
  390.                 
  391.             else:
  392.                 contents = '<b>%s %s</b>' % (source.uri, source.dist)
  393.                 for c in source.comps:
  394.                     contents += ' %s' % c
  395.                 
  396.             if source.type in ('deb-src', 'rpm-src'):
  397.                 contents += ' %s' % _('(Source Code)')
  398.             
  399.             return contents
  400.         contents = '<b>%s</b>' % source.template.description
  401.         if source.type in ('deb-src', 'rpm-src'):
  402.             contents += ' (%s)' % _('Source Code')
  403.         
  404.         if source.comment:
  405.             contents += ' %s' % source.comment
  406.         
  407.         if source.template.child == False:
  408.             for comp in source.comps:
  409.                 if source.template.has_component(comp):
  410.                     for c in source.template.components:
  411.                         if c.name == comp:
  412.                             contents += '\n%s' % c.description
  413.                             continue
  414.                     
  415.                 contents += '\n%s' % comp
  416.             
  417.         
  418.         return contents
  419.  
  420.     
  421.     def get_comparable(self, source):
  422.         '''extract attributes to sort the sources'''
  423.         cur_sys = 1
  424.         has_template = 1
  425.         has_comment = 1
  426.         is_source = 1
  427.         revert_numbers = string.maketrans('0123456789', '9876543210')
  428.         if source.template:
  429.             has_template = 0
  430.             desc = source.template.description
  431.             if source.template.distribution == self.distro:
  432.                 cur_sys = 0
  433.             
  434.         else:
  435.             desc = '%s %s %s' % (source.uri, source.dist, source.comps)
  436.             if source.comment:
  437.                 has_comment = 0
  438.             
  439.         if source.type.find('src'):
  440.             is_source = 0
  441.         
  442.         return (cur_sys, has_template, has_comment, is_source, desc.translate(revert_numbers))
  443.  
  444.     
  445.     def get_isv_sources(self):
  446.         '''Return a list of sources that are not part of the distribution'''
  447.         isv_sources = []
  448.         for source in self.sourceslist.list:
  449.             if not (source.invalid):
  450.                 if (source not in self.distro.main_sources and source not in self.distro.cdrom_sources and source not in self.distro.child_sources or source not in self.distro.disabled_sources) and source not in self.distro.source_code_sources:
  451.                     isv_sources.append(source)
  452.                     continue
  453.         
  454.         return isv_sources
  455.  
  456.     
  457.     def get_cdrom_sources(self):
  458.         '''Return the list of CDROM based distro sources'''
  459.         return self.distro.cdrom_sources
  460.  
  461.     
  462.     def get_comp_download_state(self, comp):
  463.         '''Return a tuple: the first value describes if a component is enabled
  464.        in the Internet repositories. The second value describes if the
  465.        first value is inconsistent.'''
  466.         return (comp.name in self.distro.download_comps, False)
  467.  
  468.     
  469.     def get_comp_child_state(self, template):
  470.         '''Return a tuple: the first value describes if a component is enabled
  471.        in one of the child source that matcth the given template. 
  472.        The second value describes if the first value is inconsistent.'''
  473.         comps = []
  474.         for child in self.distro.child_sources:
  475.             if child.template == template:
  476.                 comps.extend(child.comps)
  477.                 continue
  478.         
  479.         if len(comps) > 0 and len(self.distro.enabled_comps ^ set(comps)) == 0:
  480.             return (True, False)
  481.         if len(comps) > 0 and len(self.distro.enabled_comps ^ set(comps)) != 0:
  482.             return (False, True)
  483.         return (False, False)
  484.  
  485.     
  486.     def reload_sourceslist(self):
  487.         self.sourceslist.refresh()
  488.         self.sourceslist_visible = []
  489.         self.distro.get_sources(self.sourceslist)
  490.  
  491.     
  492.     def write_config(self):
  493.         '''Write the current apt configuration to file'''
  494.         conffiles = [
  495.             '/etc/apt/apt.conf.d/10periodic',
  496.             '/etc/apt/apt.conf.d/15adept-periodic-update']
  497.         for f in conffiles:
  498.             if os.path.isfile(f):
  499.                 break
  500.                 continue
  501.         else:
  502.             print 'No config found, creating one'
  503.         for periodic in conffiles:
  504.             content = []
  505.             if os.path.isfile(periodic):
  506.                 content = open(periodic, 'r').readlines()
  507.                 cnf = apt_pkg.Config.SubTree('APT::Periodic')
  508.                 f = open(periodic, 'w')
  509.                 for line in content:
  510.                     for key in cnf.List():
  511.                         if line.find('APT::Periodic::%s' % key) >= 0:
  512.                             break
  513.                             continue
  514.                     
  515.                 
  516.                 for i in cnf.List():
  517.                     f.write('APT::Periodic::%s "%s";\n' % (i, cnf.FindI(i)))
  518.                 
  519.                 f.close()
  520.                 continue
  521.         
  522.  
  523.     
  524.     def save_sourceslist(self):
  525.         '''Backup the existing sources.list files and write the current 
  526.        configuration'''
  527.         self.sourceslist.backup('.save')
  528.         self.sourceslist.save()
  529.  
  530.     
  531.     def _is_line_in_whitelisted_channel(self, srcline):
  532.         '''
  533.     helper that checks if a given line is in the source list
  534.     return the channel name or None if not found
  535.     '''
  536.         srcentry = SourceEntry(srcline)
  537.         if os.path.exists(self.CHANNEL_PATH):
  538.             for f in glob.glob('%s/*.list' % self.CHANNEL_PATH):
  539.                 for line in open(f):
  540.                     if line.strip().startswith('#'):
  541.                         continue
  542.                     
  543.                     if srcentry == SourceEntry(line):
  544.                         return os.path.splitext(os.path.basename(f))[0]
  545.                 
  546.             
  547.         
  548.  
  549.     
  550.     def check_and_add_key_for_whitelisted_channels(self, srcline):
  551.         '''
  552.     helper that adds the gpg key of the channel to the apt
  553.     keyring *if* the channel is in the whitelist
  554.     /usr/share/app-install/channels
  555.     '''
  556.         channel = self._is_line_in_whitelisted_channel(srcline)
  557.         if channel:
  558.             keyp = '%s/%s.key' % (self.CHANNEL_PATH, channel)
  559.             if os.path.exists(keyp):
  560.                 subprocess.call([
  561.                     'apt-key',
  562.                     'add',
  563.                     keyp])
  564.             
  565.         
  566.  
  567.     
  568.     def add_source_from_line(self, line):
  569.         '''
  570.     Add a source with the given apt line and auto-add
  571.     signing key if we have it in the whitelist
  572.     '''
  573.         self.check_and_add_key_for_whitelisted_channels(line)
  574.         self.sourceslist.list.append(SourceEntry(line))
  575.         self.set_modified_sourceslist()
  576.  
  577.     
  578.     def remove_source(self, source):
  579.         '''Remove the given source'''
  580.         self.sourceslist.remove(source)
  581.         self.set_modified_sourceslist()
  582.  
  583.     
  584.     def add_key(self, path):
  585.         '''Add a gnupg key to the list of trusted software vendors'''
  586.         if not os.path.exists(path):
  587.             return False
  588.         
  589.         try:
  590.             self.apt_key.add(path)
  591.             return True
  592.         except:
  593.             os.path.exists(path)
  594.             return False
  595.  
  596.  
  597.     
  598.     def remove_key(self, fingerprint):
  599.         '''Remove a gnupg key from the list of trusted software vendors'''
  600.         
  601.         try:
  602.             self.apt_key.rm(fingerprint)
  603.             return True
  604.         except:
  605.             return False
  606.  
  607.  
  608.  
  609. if __name__ == '__main__':
  610.     sp = SoftwareProperties()
  611.     print sp.get_release_upgrades_policy()
  612.     sp.set_release_upgrades_policy(0)
  613.  
  614.